#include "nfa.h"

Edge::Edge(int t, Node* s, Node* e) : type(t), start(s), end(e) {

}
const int Edge::NULL_TYPE = 1313;
Node::Node(int t) : type(t), id(0) {}

const int Node::NORMAL_TYPE = 0;
const int Node::NULL_TYPE = 1313;
const int Node::START_TYPE = 1314;
const int Node::END_TYPE = 1315;
void Node::addEdge(int t, Node* dst) {
	Edge e(t, this, dst);
	adjs[t].emplace_back(e);
	dst->in.emplace_back(e);
}
std::vector<Edge> Node::getEdgeOf(int t) {
	std::vector<Edge> edges;
	if (adjs.find(t) != adjs.end()) {
		return adjs[t];
	}
	return std::vector<Edge>();
}


std::vector<Edge> Node::getAdjEdges() {
	std::vector<Edge> edges;
	for (std::pair<int, std::vector<Edge>> pair : adjs) {
		for (Edge e : pair.second) {
			edges.emplace_back(e);
		}
	}
	return edges;
}

void Node::removeEdge(const Edge& e) {
	std::vector<Edge>& edges = adjs[e.type];
	size_t i = 0;
	for (; i < edges.size(); ++i) {
		if (edges[i].end == e.end) {
			break;
		}
	}
	for (; i < edges.size() - 1; ++i) {
		edges[i] = edges[i + 1];
	}
	edges.pop_back();
}

void Node::changeTo(const Edge& edge, Node* newNode) {
	removeEdge(edge);
	addEdge(edge.type, newNode);
}

RangeNode::RangeNode(int t, int s, int e, Node* endNode) : Node(t), endNode(endNode) {
	start.push_back(s);
	end.push_back(e);
}
RangeNode::RangeNode(Node* endNode) : Node(RangeNode::RANGE_TYPE), endNode(endNode) {
	endNode->in.emplace_back(Edge(RangeNode::RANGE_TYPE, (Node*)this, endNode));
}
void RangeNode::addRange(int s, int e) {
	start.push_back(s);
	end.push_back(e);
}

const int RangeNode::RANGE_TYPE = 1316;

void RangeNode::changeTo(const Edge& edge, Node* newNode) {
	if (edge.type == RangeNode::RANGE_TYPE)
		endNode = newNode;
	else
		Node::changeTo(edge, newNode);
}

std::vector<Edge> RangeNode::getEdgeOf(int t) {
	std::vector<Edge> edges;
	for (size_t i = 0; i < start.size(); ++i) {
		if (start[i] <= t && t <= end[i]) {
			edges.emplace_back(Edge(RangeNode::RANGE_TYPE, this, endNode));
		}
	}
	for (const Edge& edge : Node::getEdgeOf(t)) {
		edges.emplace_back(edge);
	}
	return edges;
}

NFA::NFA() : start(nullptr), end(nullptr) {}
NFA::NFA(Node* s, Node *e) : start(s), end(e) {}
bool NFA::isValid() {
	return start != nullptr || end != nullptr;
}